#pragma once

/**
 * @file fifo_sequencer.h
 * @brief FIFO序列器定义
 *
 * 本文件定义了交易所的FIFO序列器（FIFOSequencer）组件。
 * FIFO序列器负责收集客户端请求，根据接收时间对其进行排序，
 * 然后将排序后的请求发送给匹配引擎进行处理。
 * 这确保了订单处理的公平性和时间优先原则。
 *
 * @author 原作者
 * @date 未知
 */

#include "common/thread_utils.h"
#include "common/macros.h"

#include "order_server/client_request.h"

namespace Exchange {
  /**
   * @brief 订单服务器/FIFO序列器中未处理客户端请求消息的最大数量
   * 
   * 该常量定义了所有TCP连接中未处理客户端请求消息的最大数量。
   * 如果未处理请求数量超过该限制，将触发致命错误。
   */
  constexpr size_t ME_MAX_PENDING_REQUESTS = 1024;

  /**
   * @brief FIFO序列器类
   * 
   * FIFO序列器负责收集客户端请求，根据接收时间对其进行排序，
   * 然后将排序后的请求发送给匹配引擎进行处理。
   * 这确保了订单处理的公平性和时间优先原则，即先接收到的请求先处理。
   * 
   * 序列器维护一个未处理请求的队列，在调用sequenceAndPublish方法时执行排序和发布操作。
   */
  class FIFOSequencer {
  public:
    /**
     * @brief 构造函数
     * 
     * 初始化FIFO序列器，设置无锁队列指针和日志记录器。
     * 
     * @param client_requests 客户端请求无锁队列指针，用于发送请求给匹配引擎
     * @param logger 日志记录器指针，用于记录序列器的操作和状态
     */
    FIFOSequencer(ClientRequestLFQueue *client_requests, Logger *logger)
        : incoming_requests_(client_requests), logger_(logger) {
    }

    /**
     * @brief 析构函数
     * 
     * 清理FIFO序列器资源。
     * 当前实现为空，因为没有需要特别清理的资源。
     */
    ~FIFOSequencer() {
    }

    /**
     * @brief 将客户端请求加入队列
     * 
     * 将客户端请求加入待处理队列中，但不立即处理。
     * 请求将在调用sequenceAndPublish()方法时进行排序和处理。
     * 如果待处理请求数量超过限制，将触发致命错误。
     * 
     * @param rx_time 请求的接收时间，以纳秒为单位
     * @param request 客户端请求对象的引用
     */
    auto addClientRequest(Nanos rx_time, const MEClientRequest &request) {
      // 检查待处理请求队列是否已满
      if (pending_size_ >= pending_client_requests_.size()) {
        FATAL("Too many pending requests");
      }
      // 将请求及其接收时间添加到待处理队列中
      pending_client_requests_.at(pending_size_++) = std::move(RecvTimeClientRequest{rx_time, request});
    }

    /**
     * @brief 排序并发布待处理的客户端请求
     * 
     * 根据接收时间对待处理的客户端请求进行升序排序，
     * 然后将排序后的请求写入无锁队列，供匹配引擎消费。
     * 这确保了订单处理的时间优先原则，即先接收到的请求先处理。
     * 处理完所有请求后，待处理队列将被清空。
     */
    auto sequenceAndPublish() {
      // 如果没有待处理的请求，直接返回
      if (UNLIKELY(!pending_size_))
        return;

      // 记录开始处理请求的日志
      logger_->log("%:% %() % Processing % requests.\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_), pending_size_);

      // 根据接收时间对待处理的请求进行升序排序
      std::sort(pending_client_requests_.begin(), pending_client_requests_.begin() + pending_size_);

      // 处理每个排序后的请求
      for (size_t i = 0; i < pending_size_; ++i) {
        const auto &client_request = pending_client_requests_.at(i);

        // 记录将请求写入FIFO的日志
        logger_->log("%:% %() % Writing RX:% Req:% to FIFO.\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_),
                     client_request.recv_time_, client_request.request_.toString());

        // 获取无锁队列中的下一个可写位置
        auto next_write = incoming_requests_->getNextToWriteTo();
        // 将请求移动到队列中
        *next_write = std::move(client_request.request_);
        // 更新队列的写入索引
        incoming_requests_->updateWriteIndex();
        // 记录写入队列的性能指标
        TTT_MEASURE(T2_OrderServer_LFQueue_write, (*logger_));
      }

      // 清空待处理队列
      pending_size_ = 0;
    }

    /// Deleted default, copy & move constructors and assignment-operators.
    FIFOSequencer() = delete;

    FIFOSequencer(const FIFOSequencer &) = delete;

    FIFOSequencer(const FIFOSequencer &&) = delete;

    FIFOSequencer &operator=(const FIFOSequencer &) = delete;

    FIFOSequencer &operator=(const FIFOSequencer &&) = delete;

  private:
    /**
     * @brief 客户端请求无锁队列指针
     * 
     * 用于发布客户端请求，供匹配引擎消费。
     * 这个无锁队列实现了序列器和匹配引擎之间的高效通信。
     */
    ClientRequestLFQueue *incoming_requests_ = nullptr;

    std::string time_str_;  ///< 用于日志记录的时间字符串缓冲区
    Logger *logger_ = nullptr;  ///< 日志记录器指针，用于记录序列器的操作和状态

    /**
     * @brief 带接收时间的客户端请求结构体
     * 
     * 封装了客户端请求及其软件接收时间。
     * 这个结构体用于实现基于接收时间的排序。
     */
    struct RecvTimeClientRequest {
      Nanos recv_time_ = 0;  ///< 请求的接收时间，以纳秒为单位
      MEClientRequest request_;  ///< 客户端请求对象

      /**
       * @brief 比较运算符重载
       * 
       * 根据接收时间比较两个请求的先后顺序。
       * 用于实现基于接收时间的升序排序。
       * 
       * @param rhs 右操作数，要比较的另一个请求
       * @return 如果当前请求的接收时间早于右操作数，返回true；否则返回false
       */
      auto operator<(const RecvTimeClientRequest &rhs) const {
        return (recv_time_ < rhs.recv_time_);
      }
    };

    /**
     * @brief 待处理客户端请求队列
     * 
     * 存储待处理的客户端请求，初始状态下未排序。
     * 在调用sequenceAndPublish方法时，这些请求将根据接收时间进行排序。
     */
    std::array<RecvTimeClientRequest, ME_MAX_PENDING_REQUESTS> pending_client_requests_;
    size_t pending_size_ = 0;  ///< 当前待处理请求的数量
  };
}
